import React from "react";

class Hello extends React.Component {
  state = {
    count: 1,
    name: "张三",
  };

  /**
   * 组件是否应该更新呢
   *
   * PS:
   *    1. 该钩子函数是实现组件性能优化的一个点，它可以用来阻止无用的 ReRender
   *    2. 该钩子必须要返回一个 boolean ，默认返回 true
   *      false - 阻止更新流程
   *      true  - 不阻止更新流程
   *    3. PureComponent 内部帮我们实现了 shouldComponentUpdate，这时我们不要两者都用会报错
   *    4. 参数
   *      1. nextProps  最新的 Props
   *      2. nextState  最新的 State
   *    5. 该函数内我们一般是判断当前数据与最新数据然后有条件的来决定要不要阻止更新
   *      1. 最新数据如何获取：从参数上取
   *      2. 当前数据如何获取：this
   */
  shouldComponentUpdate(nextProps, nextState) {
    console.log("=== Hello shouldComponentUpdate");
    // console.log("=== nextState", nextState);

    /**
     * 当 最新的 count 为奇数时就不更新
     */
    // return nextState.count % 2 === 0;

    /**
     * 当 最新的 count 与 现有 count 一致时阻止 更新
     */
    // return this.state.count !== nextState.count;

    /**
     * 比较新旧 State，
     *    错误写法：nextState !== this.state
     *    正确逻辑：
     *        1. 将 nextState, oldState 所有属性弄成一个 属性集合数组
     *        2. 判断数组长度是否相等，如果长度不等直接 return true。否则继续下面的流程
     *        3. 循环比较他们之间同名的属性的值，有一个不等就的 return true。否则 return false
     */
    const oldStateKeys = Object.keys(this.state);
    const newStateKeys = Object.keys(nextState);
    if (oldStateKeys.length !== newStateKeys.length) {
      return true;
    }

    for (let key of newStateKeys) {
      if (!Object.is(this.state[key], nextState[key])) {
        return true;
      }
      // if (this.state[key] !== nextState[key]) {
      //   return true;
      // }
    }

    return false;
  }

  handleClickOne = () => {
    /**
     * 直接修改 state 数据，然后通过 使用 forceUpdate 引起组件重新渲染
     * 该方案不推荐
     */
    this.state.count++;
    this.forceUpdate();
  };

  handleClickTwo = () => {
    this.setState((state) => ({
      count: state.count === 3 ? 3 : state.count + 1,
    }));
  };

  handleClickThree = () => {
    this.setState((state) => ({
      name: state.name === "张三~~~" ? "张三~~~" : state.name + "~",
    }));
  };

  render() {
    console.log("=== Hello Render");
    return (
      <div>
        <h2>
          Hello, {this.state.count}, {this.state.name}
        </h2>
        <button onClick={this.handleClickOne}>强制更新</button>
        <button onClick={this.handleClickTwo}>普通更新</button>
        <button onClick={this.handleClickThree}>普通更新Name</button>
      </div>
    );
  }
}

class App extends React.Component {
  render() {
    return (
      <div>
        <h1>App</h1>
        <Hello />
      </div>
    );
  }
}

export default App;
